#include "dvc_config.h"
#include "dvc_cmd_frame.h"
#include "dvc_debug.h"
#include "dvc_log.h"
#include "string.h"

#define DVC_CONTROL_DEBUG 1

#if DVC_CONTROL_DEBUG
#include "stdio.h"
#define log_write printf
#else
#define log_write(x)
#endif

uint8_t dvc_config_init_default(dvc_t dvc)
{
    if (!dvc)
        return 1;
    dvc_config_user_cfg_sync(dvc);
    uint8_t failed = dvc_config_commit(dvc);
#ifdef DVC_ENABLE_EVENT_LOG
    dvc_log_event_t event_log = {
        .timestamp = dvc->tick,
        .event = DVC_EVENT_TYPE_UPDATE_USER_CFG,
        .flag = DVC_EVENT_FLAG_AFE,
        .state = failed,
    };
    dvc_log_event_push(dvc, &event_log);
#endif
    return failed;
}

uint8_t dvc_config_check(dvc_t dvc)
{
    // 检查dvc是否为空
    if (!dvc)
        return 1;
    dvc_reg_cfg0_t cfg0 = {0};
    dvc_reg_cfg1_t cfg1 = {0};
    if (dvc_frame_read_check(dvc, dvc_cmd_read_cfg0, (uint8_t *)&cfg0, sizeof(cfg0)))
    {
        log_write("Failed to read cfg0 data\n");
        return 1;
    }

    if (dvc_frame_read_check(dvc, dvc_cmd_read_cfg1, (uint8_t *)&cfg1, sizeof(cfg1)))
    {
        log_write("Failed to read cfg1 data\n");
        return 1;
    }

    if (memcmp(&cfg0, &dvc->cfg.cfg0, sizeof(cfg0)) || memcmp(&cfg1, &dvc->cfg.cfg1, sizeof(cfg1)))
    {
        log_write("cfg data not match\n");

#ifdef DVC_ENABLE_EVENT_LOG
        dvc_log_event_t event_log = {
            .timestamp = dvc->tick,
            .event = DVC_EVENT_TYPE_AFE_CFG_ERR,
            .flag = DVC_EVENT_FLAG_AFE,
            .state = 1,
        };
        dvc_log_event_push(dvc, &event_log);
#endif
        return 1;
    }

    return 0;
}

uint8_t dvc_config_commit(dvc_t dvc)
{
    // 检查dvc是否为空
    if (!dvc)
        return 1;
    // 检查是否成功写入cfg0数据
    if (dvc_frame_write_check(dvc, dvc_cmd_write_cfg0, (uint8_t *)&dvc->w_cfg.cfg0, sizeof(dvc->w_cfg.cfg0)))
    {
        log_write("Failed to write cfg0 data\n");
        return 1;
    }

    // 检查是否成功写入cfg1数据
    if (dvc_frame_write_check(dvc, dvc_cmd_write_cfg1, (uint8_t *)&dvc->w_cfg.cfg1, sizeof(dvc->w_cfg.cfg1)))
    {
        log_write("Failed to write cfg1 data\n");
        return 1;
    }

    // 将w_cfg中的数据复制到cfg中
    memcpy(&dvc->cfg, &dvc->w_cfg, sizeof(dvc->w_cfg));
    return 0;
}
/* 初始化 用户的配置(不发送到AFE芯片, 需手动提交配置)  */
void dvc_config_user_cfg_sync(dvc_t dvc)
{
    // 如果dvc为空，则返回
    if (!dvc)
        return;
    // 将用户配置中的AFE电池数量赋值给dvc
    dvc->bat_num = dvc->user_cfg.afe.bat_num;
    // 将用户配置中的电流电阻赋值给dvc
    dvc->current_R = dvc->user_cfg.current_R;
    // 将用户配置中的电池容量 mA 转换成1小时的值 赋值给dvc的库仑计
    dvc->coulomb_counter.bat_mA = dvc->user_cfg.bat_mAH * 3600.0f;
    // 将用户配置中的电压校准值赋值给dvc
    dvc->calib.voltage = dvc->user_cfg.calib.voltage;
    // 将用户配置中的电流校准值赋值给dvc
    dvc->calib.current = dvc->user_cfg.calib.current;

    // 定义默认配置cfg0和cfg1
    dvc_reg_cfg0_t cfg0 = DVC_DEFAULT_CFG_0;
    dvc_reg_cfg1_t cfg1 = DVC_DEFAULT_CFG_1;
    // 将默认配置赋值给dvc
    dvc->w_cfg.cfg0 = cfg0;
    dvc->w_cfg.cfg1 = cfg1;

    // 将用户配置中的AFE充电状态点赋值给dvc
    dvc->w_cfg.cfg0.cs_pt = dvc->user_cfg.afe.cs_pt;
    // 将用户配置中的AFE电压状态点赋值给dvc
    dvc->w_cfg.cfg0.vs_pt = dvc->user_cfg.afe.vs_pt;

    // 将用户配置中的AFE过压阈值赋值给dvc
    dvc->w_cfg.cfg1.ovt = dvc->user_cfg.afe.ovt;
    // 将用户配置中的AFE欠压阈值赋值给dvc
    dvc->w_cfg.cfg1.uvt = dvc->user_cfg.afe.uvt;
    // 将用户配置中的AFE过流阈值赋值给dvc
    dvc->w_cfg.cfg1.occt = dvc->user_cfg.afe.occt;
    // 将用户配置中的AFE过流时间阈值赋值给dvc
    dvc->w_cfg.cfg1.ocdt = dvc->user_cfg.afe.ocdt;
    // 将用户配置中的AFE过流断电阈值赋值给dvc
    dvc->w_cfg.cfg1.ocdd = dvc->user_cfg.afe.ocdd;
    // 将用户配置中的AFE过流断电时间阈值赋值给dvc
    dvc->w_cfg.cfg1.occd = dvc->user_cfg.afe.occd;
    // 将用户配置中的AFE短路断电阈值赋值给dvc
    dvc->w_cfg.cfg1.scdd = dvc->user_cfg.afe.scdd;
    // 将用户配置中的AFE短路断电时间阈值赋值给dvc
    dvc->w_cfg.cfg1.scdt = dvc->user_cfg.afe.scdt;
    // 将用户配置中的AFE充电电流增益赋值给dvc
    dvc->w_cfg.cfg1.cp_gc = dvc->user_cfg.afe.cp_gc;
}

/* 更新 用户的配置(会发送到AFE芯片)  */
uint8_t dvc_config_user_cfg_update(dvc_t dvc, dvc_user_cfg_t *cfg)
{
    if (!dvc || !cfg || !memcmp(cfg, &dvc->user_cfg, sizeof(dvc_user_cfg_t)))
        return 1;
    dvc->user_cfg = *cfg;
    dvc_config_user_cfg_sync(dvc);
    uint8_t failed = dvc_config_commit(dvc);
#ifdef DVC_ENABLE_EVENT_LOG
    dvc_log_event_t event_log = {
        .timestamp = dvc->tick,
        .event = DVC_EVENT_TYPE_UPDATE_USER_CFG,
        .flag = DVC_EVENT_FLAG_USER,
        .state = failed,
    };
    dvc_log_event_push(dvc, &event_log);
#endif
    if (dvc->ops && dvc->ops->save_config)
    {
        failed = dvc->ops->save_config(dvc->ops->user_data, "afe_config", (uint8_t *)&dvc->user_cfg, sizeof(dvc_user_cfg_t));
        failed = !failed;
#ifdef DVC_ENABLE_EVENT_LOG
        event_log.event = DVC_EVENT_TYPE_SAVE_USER_CFG;
        event_log.flag = DVC_EVENT_FLAG_AFE,
        event_log.state = failed,
        dvc_log_event_push(dvc, &event_log);
#endif
    }
    return failed;
}

uint8_t dvc_read_user_config(dvc_t dvc)
{
    if (!dvc)
        return 1;
    dvc_user_cfg_t dcfg = DVC_DEFAULT_USER_CFG;
    if (dvc->ops->get_config)
    {
        uint8_t len = dvc->ops->get_config(dvc->ops->user_data, "afe_config", (uint8_t *)&dcfg);
#ifdef DVC_ENABLE_EVENT_LOG
        dvc_log_event_t event_log = {
            .timestamp = dvc->tick,
            .event = DVC_EVENT_TYPE_GET_USER_CFG,
            .flag = DVC_EVENT_FLAG_AFE,
            .state = !len,
        };
        dvc_log_event_push(dvc, &event_log);
#endif
    }
    dvc->user_cfg = dcfg;
    return 0;
}
struct dvc_hitstory
{
    const char *const name;
    const uint16_t offset;
    const uint8_t size;
};
static const struct dvc_hitstory dvc_hitstory_members[] = {
    {.name = "coulomb", .offset = offsetof(dvc_s, coulomb_counter.chg), .size = sizeof(dvc_coulomb_counter_t) * 3},
    {.name = "rmA", .offset = offsetof(dvc_s, coulomb_counter.bat_rmA), .size = sizeof(float)},
    {.name = "day", .offset = offsetof(dvc_s, last_day), .size = sizeof(uint32_t)},
};
static const uint8_t dvc_hitstory_members_num = sizeof(dvc_hitstory_members) / sizeof(dvc_hitstory_members[0]);
uint8_t dvc_hitstory_restore(dvc_t dvc)
{
    if (!dvc || !dvc->ops || !dvc->ops->get_config)
        return 1;
    for (uint8_t i = 0; i < dvc_hitstory_members_num; i++)
    {
        struct dvc_hitstory *item = &dvc_hitstory_members[i];
        uint8_t len =
            dvc->ops->get_config(dvc->ops->user_data, item->name, (intptr_t)dvc + (void *)item->offset);
        if (len != item->size)
            log_write("%s : Got size(%d) != now size(%d)\n", item->name, len, item->size);
    }
    return 0;
}
uint8_t dvc_hitstory_store(dvc_t dvc)
{
    if (!dvc || !dvc->ops || !dvc->ops->save_config)
        return 1;
    for (uint8_t i = 0; i < dvc_hitstory_members_num; i++)
    {
        struct dvc_hitstory *item = &dvc_hitstory_members[i];
        dvc->ops->save_config(dvc->ops->user_data, item->name, (intptr_t)dvc + (void *)item->offset, item->size);
    }
    return 0;
}

uint16_t dvc_user_config_print_to(dvc_user_cfg_t *cfg, void *buf, uint16_t len)
{
    if (!cfg || !buf || len < 48)
        return 0;
    char *p = (char *)buf;
    uint16_t l = 0;
    l += snprintf(&p[l], len - l, "{");
    l += snprintf(&p[l], len - l, "\"uR\": %ld,", cfg->current_R);
    l += snprintf(&p[l], len - l, "\"mAH\": %lu,", cfg->bat_mAH);
    l += snprintf(&p[l], len - l, "\"aes\": {");
    l += snprintf(&p[l], len - l, "\"start\": %f,", cfg->aes.max);
    l += snprintf(&p[l], len - l, "\"end\": %f", cfg->aes.min);
    l += snprintf(&p[l], len - l, "},\"afe\": {");
    l += snprintf(&p[l], len - l, "\"covt\": %u,", cfg->afe.covt);
    l += snprintf(&p[l], len - l, "\"cuvt\": %u,", cfg->afe.cuvt);
    l += snprintf(&p[l], len - l, "\"cccd\": %u,", cfg->afe.cccd);
    l += snprintf(&p[l], len - l, "\"cscd\": %u,", cfg->afe.cscd);
    l += snprintf(&p[l], len - l, "\"ovt\": %u,", cfg->afe.ovt);
    l += snprintf(&p[l], len - l, "\"uvt\": %u,", cfg->afe.uvt);
    l += snprintf(&p[l], len - l, "\"occt\": %u,", cfg->afe.occt);
    l += snprintf(&p[l], len - l, "\"ocdt\": %u,", cfg->afe.ocdt);
    l += snprintf(&p[l], len - l, "\"ocdd\": %u,", cfg->afe.ocdd);
    l += snprintf(&p[l], len - l, "\"occd\": %u,", cfg->afe.occd);
    l += snprintf(&p[l], len - l, "\"scdd\": %u,", cfg->afe.scdd);
    l += snprintf(&p[l], len - l, "\"scdt\": %u,", cfg->afe.scdt);
    l += snprintf(&p[l], len - l, "\"cp_gc\": %u,", cfg->afe.cp_gc);
    l += snprintf(&p[l], len - l, "\"cs_pt\": %u,", cfg->afe.cs_pt);
    l += snprintf(&p[l], len - l, "\"vs_pt\": %u,", cfg->afe.vs_pt);
    l += snprintf(&p[l], len - l, "\"bat_num\": %u,", cfg->afe.bat_num);
    l += snprintf(&p[l], len - l, "\"calib_v\": %.3f,", cfg->calib.voltage);
    l += snprintf(&p[l], len - l, "\"calib_c\": %.3f", cfg->calib.current);
    l += snprintf(&p[l], len - l, "}}");
    return l;
}